package com.example.coroutines

import kotlinx.coroutines.*
import org.junit.Test


/**
 * 协程启动模式测试
 *
 * @author zhouronghua
 * @time 2021/12/28 9:36 下午
 */
public class StartModeTest {

    /**
     * 默认启动模式
     * 说明: 协程创建后立即执行，在调度前如果被取消，
     * 其将直接进入取消相应的状态
     *
     */
    @Test
    fun testDefaultMode() {
        println("step 1")
        val job = GlobalScope.launch(start = CoroutineStart.DEFAULT) {
            println("进入默认协程")
            val job2 = async {
                for (index in 1..10000) {
                    println("$index")
                }
            }
            job2.await()
            // 挂起5秒
            println("step 2 挂起默认5秒")
            // 挂起5秒
            delay(5000)
            // 继续打印
            println("step 3")
        }
        println("主线程等待0.1秒")
        // 休眠两秒以后step2能够打印出来
        runBlocking {
            delay(100)
        }
        println("step 4 取消协程任务")
        // 取消协程任务
        job.cancel()
        runBlocking {
            delay(10000)
        }
        println("step 5 主线程完成")
    }

    /**
     * 原子模式启动模式
     * 说明: 协程创建后立即执行，在调度前如果被取消，
     * 协程执行到第一个挂起点前不会取消
     *
     */
    @Test
    fun testAtomicMode() {
        println("step 1 测试原子模式协程")
        val job = GlobalScope.launch(start = CoroutineStart.ATOMIC) {
            println("进入原子协程")
            val job2 = async {
                for (index in 1..10000) {
                    println("$index")
                }
            }
            // 挂起5秒
            job2.await()
            println("step 2 挂起原子协程5秒")
            // 挂起点之前的任务如果执行，则会全部执行完成（要么未执行前取消全部不执行）
            delay(5000)
            // 继续打印
            println("step 3 原子协程结束")
        }
//        Thread.sleep(2000)
        println("主线程等待1秒")
        runBlocking {
            delay(100)
        }
        println("step 4 取消协程任务")
        // 取消协程任务
        job.cancel()
        runBlocking {
            delay(10000)
        }
        println("step 5 主线程完成")
    }

    /**
     * 懒启动模式
     * 说明: 只要协程被真正需要时，包括协程的start、join、await等函数时才开始调度，
     * 如果调度前被取消，那么该协程直接进入异常结束状态。
     *
     */
    @Test
    fun testLazyMode() {
        println("step 1 测试懒启动模式协程")
        val job = GlobalScope.launch(start = CoroutineStart.LAZY) {
            println("step 2 挂起懒启动协程5秒")
            // 挂起5秒
            delay(1000)
            // 继续打印
            println("step 3 懒启动协程结束")
        }
        println("step 4 阻塞等待2秒")
//        runBlocking {
//            delay(2000)
//        }
        println("step 5 启动协程任务")
        // 启动协程任务（此时协程中的任务才开始执行，类似于懒加载）
        job.start()
        println("step 6 主线程完成")
        runBlocking {
            delay(2000)
        }
    }

    /**
     * 无调度启动模式
     * 说明: 协程创建后立即在当前函数调用栈中执行，直到遇到第一个真正挂起点
     * step 1 测试无调度启动模式协程
     * step 2 挂起无调度启动协程3秒
     * step 4 阻塞等待2秒
     * step 5 启动协程任务
     * step 6 主线程完成
     * step 3 无调度启动协程结束
     */
    @Test
    fun testUndispatchedMode() {
        println("step 1 测试无调度启动模式协程")
        val job = GlobalScope.launch(start = CoroutineStart.UNDISPATCHED) {
            println("step 2 挂起无调度启动协程3秒")
            // 挂起5秒
            delay(3000)
            // 继续打印
            println("step 3 无调度启动协程结束")
        }
        println("step 4 阻塞等待2秒")
        runBlocking {
            delay(2000)
        }
        println("step 5 启动协程任务")
        // 启动协程任务（此时协程中的任务才开始执行，类似于懒加载）
        job.start()
        println("step 6 主线程完成")
        runBlocking {
            delay(2000)
        }
    }

    /**
     * 测试无调度启动模式线程模式
     * 说明：主线程协程中创建的UNDISPATCHED协程，还是运行的主协程中，因为不需要
     * 进行调度器调度
     */
    @Test
    fun testThreadUndispatchedMode() = runBlocking {
        println(" main thread in: ${Thread.currentThread().name}")
        // 主线程中创建一个异步协程任务，调度器是IO，无调度启动模式，
        // 不转发的话，主线程创建协程，协程在主线程执行
        val job = async(context = Dispatchers.IO, start = CoroutineStart.UNDISPATCHED) {
            // 在主线程中执行协程
            println(" current Thread name in: ${Thread.currentThread().name}")
        }
    }
}